(*EXERCICIO 1*)
let rec mapdoble f1 f2 = function
    [] -> []
  | [h1] -> [f1 h1]
  | h1::h2::t -> (f1 h1)::(f2 h2)::(mapdoble f1 f2 t)

(*
- : ('a -> 'b) -> ('a -> 'b) -> 'a list -> 'b list = <fun>
*)

(*
#mapdoble (function x -> x*2) (function x -> "x") [1;2;3;4;5];;
This expression has type string but is here used with type int
Da un erro porque o tipo das duas funcions debe se-lo mesmo


#let y = function x -> 5 in mapdoble y;;
- : ('_a -> int) -> '_a list -> int list = <fun>
*)



(*EXERCICIO 2*)
let rec primero_que_cumple p = function
    [] -> raise Not_found
  | h::t -> if (p h) then h else primero_que_cumple p t

(*
- : ('a -> bool) -> 'a list -> 'a = <fun>
*)


let existe p lista =
  try 
    (match primero_que_cumple p lista with
      x -> true)
  with 
    Not_found -> false  
(*
val existe : ('a -> bool) -> 'a list -> bool = <fun>
*)


let asociado clave conxunto =
  snd (primero_que_cumple (function (a,_) -> a=clave ) conxunto)
  
(*
val asociado : 'a -> ('a * 'b) list -> 'b = <fun>
*)


(*EXERCICIO 3*)
type 'a arbol_binario = 
    Vacio
  | Nodo of 'a * 'a arbol_binario * 'a arbol_binario

(*
val in_orden : 'a arbol_binario -> 'a list = <fun>
*)

let rec in_orden = function
    Vacio -> []
  | Nodo (v,h1,h2) -> in_orden h1 @ v :: in_orden h2 

(*
val in_orden : 'a arbol_binario -> 'a list = <fun>
*)

let rec pre_orden = function
    Vacio -> []
  | Nodo (v,h1,h2) -> v :: pre_orden h1 @ pre_orden h2 

(*
val pre_orden : 'a arbol_binario -> 'a list = <fun>
*)

let rec post_orden = function
    Vacio -> []
  | Nodo (v,h1,h2) -> post_orden h1 @ post_orden h2 @ [v] 

(*
val post_orden : 'a arbol_binario -> 'a list = <fun>
*)

(*
let rec anchura = function
    Vacio -> []
  | Nodo(v0,Nodo(v1,h11,h12),Nodo(v2,h21,h22)) -> v0::v1::v2 @ anchura h11 @ anchura h12 @ anchura h21 @ anchura h22   



let t = Nodo(3, Nodo(2,Nodo(13,Vacio,Vacio),Nodo(14,Vacio,Vacio)), Nodo(5,Nodo(4,Vacio,Vacio),Nodo(1,Vacio,Vacio)))
*)


type 'a conjunto = Conjunto of 'a list
let c_vacio = Conjunto []

(*
val c_vacio : 'a conjunto = Conjunto []
*)

let es_vacio = function
    Conjunto [] -> true
  | _ -> false 

(*
val es_vacio : 'a conjunto -> bool = <fun>
*)
	
let pertenece x = function 
    Conjunto c -> List.exists (function a -> a == x) c

(*
val pertenece : 'a -> 'a conjunto -> bool = <fun>
*)
	
let agregar x = function
    Conjunto c -> if pertenece x (Conjunto c) then raise (Failure "Elemento existente")
    else Conjunto (x::c)
  
(*
val agregar : 'a -> 'a conjunto -> 'a conjunto = <fun>
*)
 
let rec conjunto_of_list = function
    [] -> Conjunto []
  | h::t -> agregar h (conjunto_of_list t)

(*
val conjunto_of_list : 'a list -> 'a conjunto = <fun>
*)

let rec suprimir x = function 
  Conjunto [] -> failwith "Suprimir: Non existe"
| Conjunto (h::t) when h=x-> Conjunto t
| Conjunto (h::t) -> agregar h (suprimir x (Conjunto t))

(*
val suprimir : 'a -> 'a conjunto -> 'a conjunto = <fun>
*)

let cardinal (Conjunto c) = List.length c;; 

(*
val cardinal : 'a conjunto -> int = <fun>
*)

let rec union c1 = function
    Conjunto [] -> c1
  | Conjunto (h::t) -> try union (agregar h c1) (Conjunto t) with
      Failure _ -> union c1 (Conjunto t)

(*
val union : 'a conjunto -> 'a conjunto -> 'a conjunto = <fun>
*)

let rec interseccion (Conjunto c1) = function
	Conjunto [] -> Conjunto []
     |	Conjunto (h::t) -> if List.exists (function x -> x==h) c1
                           then agregar h (interseccion (Conjunto c1) (Conjunto t))
	                   else interseccion (Conjunto c1) (Conjunto t)


let rec diferencia Conjunto c = function
        Conjunto [] -> Conjunto c
    |   Conjunto (h::t) ->  

















